﻿using System.Collections.Concurrent;
using System.Net;
using System.Net.Sockets;
using System.Text;
using MySql.Data.MySqlClient;

class LicenseServer
{
    const string connectionString = "server=localhost;port=3316;user=root;password=;database=license"; // 数据库连接字符串
    private static readonly ConcurrentDictionary<int, DateTime> heartbeatRecords = new();// 记录客户端最后报告时间，用于判断是否崩溃
    private static readonly object lockObject = new();// 用于同步心跳记录更新的锁对象
    private static int clientCount = 0;// 客户端代号
    private static readonly ConcurrentDictionary<int, string> clientIdToSerialNumber = new();// 记录客户端和许可证的对应关系

    static void Main(string[] args)
    {
        Console.WriteLine("许可证服务器已启动...");

        // 启动一个新的线程，用于定期检查客户端状态
        var heartbeatThread = new Thread(CheckHeartbeats);
        heartbeatThread.IsBackground = true; 
        heartbeatThread.Start();

        // 启动TCP服务器，监听端口8080
        var server = new TcpListener(IPAddress.Any, 8080);
        server.Start();
        
        while (true)
        {
            // 接受客户端连接，并启动一个独立线程
            var client = server.AcceptTcpClient();
            clientCount++;
            var clientThread = new Thread(() => HandleClient(client, clientCount));
            clientThread.Start();
        }
    }
    
    private static void HandleClient(TcpClient client, int clientId)
    {
        try
        {
            NetworkStream stream = client.GetStream();
            byte[] buffer = new byte[1024];
            int bytesRead = stream.Read(buffer, 0, buffer.Length);
            string request = Encoding.UTF8.GetString(buffer, 0, bytesRead);
            
            string response = ProcessRequest(request, clientId);
            
            byte[] responseData = Encoding.UTF8.GetBytes(response);
            stream.Write(responseData, 0, responseData.Length);
        }
        finally
        {
            client.Close();
        }
    }

    // 处理客户端请求的函数
    static string ProcessRequest(string request, int clientId)
    {
        string[] parts = request.Split(':');
        string command = parts[0];
        clientIdToSerialNumber[clientCount] = parts[1];
        
        using var connection = new MySqlConnection(connectionString);// 连接数据库
        connection.Open();
        
        switch (command)
        {
            case "VALIDATE":  // 许可证验证
                return ValidateLicense(parts[1], connection, clientId);
            case "HEARTBEAT":  // 心跳更新
                return UpdateHeartbeat(parts[1], clientId);
            case "GENERATE": // 生成许可证
                return GenerateLicense(parts, connection);
            default:  
                return "未知命令";
        }
    }

    // 验证许可证的函数
    private static string ValidateLicense(string licenseKey, MySqlConnection connection, int clientId)
    {
        lock (lockObject)
        {
            string selectQuery = "SELECT max_users, current_users FROM licenses WHERE license_key = @key";
            using var cmd = new MySqlCommand(selectQuery, connection);
            cmd.Parameters.AddWithValue("@key", licenseKey);
            using var reader = cmd.ExecuteReader();
            
            if (reader.Read())
            {
                int maxUsers = reader.GetInt32(0); 
                int currentUsers = reader.GetInt32(1);  
                
                if (currentUsers < maxUsers)
                {
                    reader.Close();
                    
                    string updateQuery = "UPDATE licenses SET current_users = current_users + 1 WHERE license_key = @key";
                    using var updateCmd = new MySqlCommand(updateQuery, connection);
                    updateCmd.Parameters.AddWithValue("@key", licenseKey);
                    updateCmd.ExecuteNonQuery();
                    
                    heartbeatRecords[clientId] = DateTime.Now;

                    return "验证成功";
                }
                return "授权失败，人数已达上限";
            }
            return "许可证无效";
        }
    }

    // 更新心跳时间的函数
    private static string UpdateHeartbeat(string licenseKey, int clientId)
    {
        if (heartbeatRecords.ContainsKey(clientId))
        {
            heartbeatRecords[clientId] = DateTime.Now;
            return "心跳更新成功";
        }
        return "许可证无效或未激活";
    }

    // 定期检查心跳状态的函数
    private static void CheckHeartbeats()
    {
        while (true)
        {
            Thread.Sleep(10000);
            
            DateTime now = DateTime.Now;
            
            lock (lockObject)
            {
                foreach (var record in heartbeatRecords)
                {
                    if ((now - record.Value).TotalSeconds > 60)// 检查心跳时间是否超过60秒
                    {
                        int clientId = record.Key;
                        string serialNumber = clientIdToSerialNumber[clientId]; 

                        // 更新数据库，将当前使用人数减1
                        using var connection = new MySqlConnection(connectionString);
                        connection.Open();
                        string updateQuery = "UPDATE licenses SET current_users = current_users - 1 WHERE license_key = @key";
                        using var cmd = new MySqlCommand(updateQuery, connection);
                        cmd.Parameters.AddWithValue("@key", serialNumber);
                        cmd.ExecuteNonQuery();
                        
                        heartbeatRecords.TryRemove(clientId, out _);
                        
                        clientIdToSerialNumber.TryRemove(clientId, out _);
                        
                        Console.WriteLine($"客户端 {clientId} 已从活跃状态中移除。");
                    }
                }
            }
        }
    }

    // 生成序列号的函数，您可以根据实际需求来修改序列号的生成方式
    private static string GenerateLicense(string[] parts, MySqlConnection connection)
    {
        string licenseKey = Guid.NewGuid().ToString().Substring(0, 10).ToUpper();
        int maxUsers = int.Parse(parts[1]);

        lock (lockObject)
        {
            string insertQuery = "INSERT INTO licenses (license_key, max_users, current_users) VALUES (@key, @max, 0)";
            using (var cmd = new MySqlCommand(insertQuery, connection))
            {
                cmd.Parameters.AddWithValue("@key", licenseKey);
                cmd.Parameters.AddWithValue("@max", maxUsers);
                cmd.ExecuteNonQuery();
            }
        }

        Console.WriteLine($"许可证生成成功：{licenseKey}");
        return $"许可证生成成功：{licenseKey}";
    }

}
